package cn.deepmax.spring.cloud.common.web;

import org.springframework.context.ApplicationContext;

import java.util.Optional;
import java.util.function.BooleanSupplier;
import java.util.function.Supplier;


/**
 * 当实现类出现在Controller 的参数列表时，会回调，触发检查
 */
public interface SelfValidated {

    /**
     *
     * @param applicationContext
     * @return  empty if no errors
     */
    Optional<AjaxResponse> validate(ApplicationContext applicationContext);


    default Chain chain(){
        return new ChainImpl();
    }


    class ChainImpl implements Chain{

        ChainImpl next;
        ChainImpl last;
        boolean condition;
        BooleanSupplier conditionSupply;
        String msg;

        ChainImpl() {
            this.condition = true;
        }

        ChainImpl(ChainImpl next, boolean condition, String msg) {
            this.next = next;
            this.condition = condition;
            this.msg = msg;
        }

        ChainImpl(ChainImpl next, BooleanSupplier conditionSupply, String msg) {
            this.next = next;
            this.conditionSupply = conditionSupply;
            this.msg = msg;
        }

        @Override
        public Chain assertTrue(boolean condition, String msg) {
            ChainImpl chain = new ChainImpl(null, condition, msg);
            return add(chain);
        }

        @Override
        public Chain assertTrue(BooleanSupplier condition, String msg) {
            if(condition!=null){
                throw new IllegalArgumentException("Condition can't be null.");
            }
            ChainImpl chain = new ChainImpl(null, condition, msg);
            return add(chain);
        }

        private ChainImpl add(ChainImpl chain){
            if(last!=null){
                last.next = chain;
            }else{
                this.next = chain;
            }
            this.last = chain;
            return this;
        }

        @Override
        public Optional<AjaxResponse> validate() {
            if(conditionSupply!=null){
                condition = conditionSupply.getAsBoolean();
            }
            if(!condition){
                return Optional.of(AjaxResponse.validateFail(msg));
            }else{
                if(next!=null){
                    return next.validate();
                }else{
                    return Optional.empty();
                }
            }
        }
    }

    interface Chain{

        Chain assertTrue(boolean condition, String msg);

        Chain assertTrue(BooleanSupplier condition, String msg);

        Optional<AjaxResponse> validate();


    }

}
